<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>Java编程思想笔记九 | 净土</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="thinking in java; java编程思想; 图形化用户界面;">
<meta property="og:type" content="article">
<meta property="og:title" content="Java编程思想笔记九">
<meta property="og:url" content="http://howiefh.github.io/2015/02/07/thinking-in-java-note-9/index.html">
<meta property="og:site_name" content="净土">
<meta property="og:description" content="thinking in java; java编程思想; 图形化用户界面;">
<meta property="og:updated_time" content="2015-02-08T13:12:54.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Java编程思想笔记九">
<meta name="twitter:description" content="thinking in java; java编程思想; 图形化用户界面;">
  
    <link rel="alternative" href="/atom.xml" title="净土" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.ico">
  
  <link href="http://fonts.useso.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  <link rel="stylesheet" href="/css/style.css" type="text/css">
  
<script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-40492061-1', 'auto');
ga('send', 'pageview');

</script>


  
<script>
var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "//hm.baidu.com/hm.js?56d2899c5e919fbf4a7b00de5d1c31dd";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script>


</head>

<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">净土</a>
      </h1>
      
        <h2 id="subtitle-wrap">
          <a href="/" id="subtitle">乐不在外而在心，心以为乐，则是境皆乐；心以为苦，则无境不苦。</a>
        </h2>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">Home</a>
        
          <a class="main-nav-link" href="/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-github-link" class="nav-icon" href="https://github.com/howiefh" title="Github" target="_blank"></a>
        
        
          <a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed" target="_blank"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" results="0" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://howiefh.github.io"></form>
      </div>
    </div>
  </div>
</header>

      <div class="outer">
        <section id="main"><article id="post-thinking-in-java-note-9" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    
<a href="/2015/02/07/thinking-in-java-note-9/" class="article-date">
  <time datetime="2015-02-07T12:51:16.000Z" itemprop="datePublished">2015-02-07</time>
</a>


    
  <div class="article-category">
    <a class="article-category-link" href="/categories/Java/">Java</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      Java编程思想笔记九
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
		
		<div id="toc" class="toc-article">
			<h2 class="toc-title"><span>Contents</span></h2>
		
			<ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#Swing_基础"><span class="toc-number">1.</span> <span class="toc-text">Swing 基础</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#组件"><span class="toc-number">1.1.</span> <span class="toc-text">组件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#布局管理"><span class="toc-number">1.2.</span> <span class="toc-text">布局管理</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#事件"><span class="toc-number">1.3.</span> <span class="toc-text">事件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#绘图"><span class="toc-number">1.4.</span> <span class="toc-text">绘图</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Swing与并发"><span class="toc-number">2.</span> <span class="toc-text">Swing与并发</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#长期运行的任务"><span class="toc-number">2.1.</span> <span class="toc-text">长期运行的任务</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#可视化线程机制"><span class="toc-number">2.2.</span> <span class="toc-text">可视化线程机制</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#可视化编程与JavaBean"><span class="toc-number">3.</span> <span class="toc-text">可视化编程与JavaBean</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是JavaBean"><span class="toc-number">3.1.</span> <span class="toc-text">什么是JavaBean</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#使用Introspector抽取BeanInfo"><span class="toc-number">3.2.</span> <span class="toc-text">使用Introspector抽取BeanInfo</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#JavaBean与同步"><span class="toc-number">3.3.</span> <span class="toc-text">JavaBean与同步</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#对Bean更高级的支持"><span class="toc-number">3.4.</span> <span class="toc-text">对Bean更高级的支持</span></a></li></ol></li></ol>
		
		</div>
		
        <p>Swing中有一个非常令人称道的原则，称为“正交使用”。意思是，一旦你理解了库中的某个通用概念，你就可以把这个概念应用到其他地方。</p>
<h2 id="Swing_基础">Swing 基础</h2><p>Swing有它自己的专用线程来接收UI事件并更新屏幕，如果从其他线程着手对屏幕进行操作，那么就可能产生冲突和死锁。其他线程通过事件分发线程提交要执行的任务，可以通过将任务提交给SwingUtilities.invokeLater()来实现这种方式，这个方法会通过事件分发线程将任务放置到（最终将得到执行的）待执行事件队列中。程序中的所有代码都遵循这种通过SwingUtilities.invokeLater()来提交操作的方式。这包括启动程序自身，即main也不应该调用Swing方法，就像上面的程序一样，它应该向事件队列提交任务。</p>
<p>Java中设计和实现图形用户界面的工作主要有：</p>
<ol>
<li>创建组件（Component)：创建组成界面的各种元素，如按钮、文本框等。</li>
<li>指定布局（Layout）：根据具体需要排列组件的位置关系。</li>
<li>响应事件（Event）：定义图形用户界面的事件和各界面元素对不同事件的响应，从而实现图形用户界面与用户的交互功能。</li>
</ol>
<a id="more"></a>
<h3 id="组件">组件</h3><p>Swing GUI由顶层容器-中间容器-基本组件构成</p>
<ul>
<li>顶层容器，这些组件在Swing GUI层次体系的顶层，主要包括JFrame，JApplet，JDialog等</li>
<li>通用容器，具有普遍应用场合，包括Jpanel，JScrollPane，JSplitPane，JTabbedPane, JToolBar等</li>
<li>特殊容器，在GUI中起特殊作用的中间层容器，包括JInternalFrame，JLayeredPane，JRootPane等</li>
<li>基本控制组件，这些基本组件主要用于接收用户输入，它们一般能够显示简单的状态，包括JButton，JComboBox，JList，JMemu，JSlider，JTestField等</li>
<li>不可编辑的信息显示组件，完全用来显示信息的组件，包括JLabel，JProgressBar等</li>
<li>可编辑的信息显示组件，这些组件用来显示可被用户编辑修改的格式化信息，包括JTable，JFileChooser，JTree等</li>
</ul>
<p>Swing组件中，除了顶层容器组件，所有以J开头的组件都是JComponent类的子类，可以添加工具提示setToolTipText(String)</p>
<ul>
<li><p>对话框</p>
<ul>
<li>JOptionPane（简单标准的对话框）</li>
<li>ProgressMonitor（显示操作进程的对话框）</li>
<li>JColorChooser（标准对话框）</li>
<li>JFileChooser（标准对话框）</li>
<li>JDialog（可制定对话框）</li>
</ul>
</li>
<li><p>按钮类组件</p>
<ul>
<li>包括JButton，JCheckBox,JRadioButton, JMenuItem, JCheckBoxMenuItem</li>
<li>AbstractButton是一个抽象类，它是JButton，JCheckBox,JRadioButton, JMenuItem, JCheckBoxMenuItem类的父类</li>
</ul>
</li>
<li><p>文本组件</p>
<ul>
<li>JTextField</li>
<li>JPasswordField</li>
<li>JTextArea</li>
<li>JEditorPane</li>
<li>JTextPane</li>
</ul>
</li>
<li><p>标签JLable</p>
</li>
<li>列表JList</li>
<li>表格JTable</li>
<li>树JTree</li>
<li>选择框JComboBox</li>
<li>文件选择器JFileChooser</li>
<li>颜色选择器JColorChooser</li>
<li>进程条JProgressBar</li>
<li>滑动块Jslider</li>
<li>微调器JSpinner</li>
</ul>
<h3 id="布局管理">布局管理</h3><p>Java提供了下列布局管理器</p>
<ol>
<li><p>FlowLayout 流式布局管理器(JPanel的默认布局)</p>
<p> FlowLayout(int align, int hgap, int vgap)，组件按参数指定的对齐方式摆放，组件之间水平距离由hgap指定，垂直距离由vgap指定，aligh 默认居中，hgap，vgap默认5个像素。使用FlowLayout，所有组件将被压缩到它们的最小尺寸，如果重新调整视窗大小，那么布局管理器将随之重新流动所有组件。</p>
</li>
<li><p>BorderLayout 边界布局管理器(JFrame,JWindow的默认布局)</p>
<p> BorderLayout()：组件之间没有水平间隙与垂直间隙；BorderLayout(int hgap, int vgap)：指定组件之间的水平和垂直间隙</p>
<p> BorderLayout布局管理器将容器分为5个区：East, West, South, North和Center。对于除Center以外的所有位置，加入的组件被沿着一个方向压缩到最小尺寸，同时在另一个方向上拉伸到最大尺寸。不过对于Center，组件将在两个方向上同时拉伸，以覆盖中央区域。</p>
</li>
<li><p>GridLayout网格布局管理器</p>
<p> BorderLayout()：组件之间没有水平间隙与垂直间隙；BorderLayout(int hgap, int vgap)：指定组件之间的水平和垂直间隙；GridLayout(int rows, int cols, int hgap, int vgap)，容器划分为指定数目的网格，并制定组件间的水平垂直距离</p>
</li>
<li><p>GridBagLayout网格包布局管理器</p>
<p> GridBagLayout所管理的每个组件都与一个GridBagConstraints类的对象相关。这个约束对象指定了组建的显示区域在网格中的位置，以及在其显示区域中应该如何摆放组件</p>
<p> GridBagConstraints对象的定制是通过设置一个或者多个GridBagConstraints的变量来实现的：</p>
<ul>
<li>gridx,gridy指定组件左上角在网格中的行与列</li>
<li>gridwidth, gridheight指定组件显示区域所占的列数与行数</li>
<li>fill指定组件填充网格的方式</li>
<li>ipadx,ipady指定组件显示区域的内部填充</li>
<li>insets指定组件显示区域的外部填充</li>
<li>anchor指定组件在显示区域的摆放位置</li>
<li>weightx, weighty用来指定在容器大小改变是，增加或减少的孔家如何在组件间进行分配  </li>
</ul>
</li>
<li><p>BoxLayout箱式布局管理器</p>
<p> 箱式布局管理器将组件垂直摆放在一列或水平摆放的一行中，具体由BoxLayout.X_AXIS和BoxLayout.Y_AXIS指定</p>
</li>
<li><p>GroupLayout分组布局管理器</p>
<p> GroupLayout 是一个 LayoutManager，它将组件按层次分组，以决定它们在 Container 中的位置。GroupLayout 主要供生成器使用，但也可以手工编码。分组由 Group 类的实例来完成。GroupLayout 支持两种组。串行组 (sequential group) 按顺序一个接一个地放置其子元素。并行组 (parallel group) 能够以四种方式对齐其子元素。</p>
<p> 每个组可以包含任意数量的元素，其中元素有 Group、Component 或间隙 (gap)。间隙可被视为一个具有最小大小、首选大小和最大大小的不可见组件。此外，GroupLayout 还支持其值取自 LayoutStyle 的首选间隙。</p>
</li>
<li><p>CardLayout卡片布局管理器</p>
<p> CardLayout()，组件与左右上下界之间没有间隙， CardLayout(int hgap, int vgap)，参数hgap指定组件距离左右边界的间隙，参数vgap指定组件距离上下边界的间隙。</p>
<p> CardLayout常用的方法：<code>public void first (Container parent)</code>，显示第一张卡片，<code>public void next (Container parent)</code>，显示下一张卡片(如果当前是最后一张，则显示第一张)，<code>public void previous (Container parent)</code>，显示前一张卡片，<code>public void last (Container parent)</code>，显示最后一张卡片，<code>public void show (Container parent, String name)</code>，显示指定名称的组件，</p>
</li>
<li><p>无布局管理器</p>
<p> 使用setLayout(null)把容器的布局管理器设置为空。需要使用setLocation(), setSize(),setBounds()或者reshape()等方法手工设置组件大小和位置(这些方法会导致平台相关，不建议使用)</p>
</li>
</ol>
<p>第三方：FormLayout、MigLayout，TableLayout</p>
<h3 id="事件">事件</h3><p>事件处理模型中的3类对象</p>
<ul>
<li>事件<br>  当用户在界面上执行一个操作，如敲键盘、拖动或者单击鼠标，都产生了事件</li>
<li>事件源<br>  产生事件的组件就是一个事件源。如在一个Button上单击鼠标时，将产生一个ActionEvent类型的事件，这个Button就是事件源</li>
<li>事件处理器<br>  事件处理器是一个方法，该方法接收一个事件对象，对其进行解释，并做出相应的处理</li>
</ul>
<p>事件及其相应的监听器接口</p>
<table>
<thead>
<tr>
<th>事件类别</th>
<th>描述信息</th>
<th>接口名</th>
<th>方法</th>
</tr>
</thead>
<tbody>
<tr>
<td>　ActionEvent</td>
<td>激活组件</td>
<td>　　ActionListener</td>
<td>　actionPerformed(ActionEvent)</td>
</tr>
<tr>
<td>　ItemEvent</td>
<td>选择了某些项目</td>
<td>　　ItemListener</td>
<td>　itemStateChanged(ItemEvent)</td>
</tr>
<tr>
<td>　MouseEvent</td>
<td>鼠标移动</td>
<td>　　MouseMotionListener</td>
<td>　mouseDragged(MouseEvent) 　mouseMoved(MouseEvent)</td>
</tr>
<tr>
<td>  MouseEvent</td>
<td>鼠标点击等</td>
<td>　　MouseListener</td>
<td>　mousePressed(MouseEvent) 　mouseReleased(MouseEvent) 　mouseEntered(MouseEvent) 　mouseExited(MouseEvent) 　mouseClicked(MouseEvent)</td>
</tr>
<tr>
<td>　KeyEvent</td>
<td>键盘输入</td>
<td>　　KeyListener</td>
<td>　keyPressed(KeyEvent) 　keyReleased(KeyEvent) 　keyTyped(KeyEvent)</td>
</tr>
<tr>
<td>　FocusEvent</td>
<td>组件收到或失去焦点</td>
<td>　　FocusListener</td>
<td>　focusGained(FocusEvent) 　focusLost(FocusEvent)</td>
</tr>
<tr>
<td>　AdjustmentEvent</td>
<td>移动了滚动条等组件</td>
<td>　　AdjustmentListener</td>
<td>　adjustmentValueChanged(AdjustmentEvent)</td>
</tr>
<tr>
<td>　ComponentEvent</td>
<td>对象移动缩放显示隐藏等</td>
<td>　　ComponentListener</td>
<td>　componentMoved(ComponentEvent) 　componentHidden(ComponentEvent) 　componentResized(ComponentEvent) 　componentShown(ComponentEvent)</td>
</tr>
<tr>
<td>　WindowEvent</td>
<td>窗口收到窗口级事件</td>
<td>　　WindowListener</td>
<td>　windowClosing(WindowEvent) 　windowOpened(WindowEvent) 　windowIconified(WindowEvent) 　windowDeiconified(WindowEvent) 　windowClosed(WindowEvent) 　windowActivated(WindowEvent) 　windowDeactivated(WindowEvent)</td>
</tr>
<tr>
<td>　ContainerEvent</td>
<td>容器中增加删除了组件</td>
<td>　　ContainerListener</td>
<td>　componentAdded(ContainerEvent) componentRemoved(ContainerEvent)</td>
</tr>
<tr>
<td>　TextEvent</td>
<td>文本字段或文本区发生改变</td>
<td>　　TextListener</td>
<td>　textValueChanged(TextEvent)</td>
</tr>
</tbody>
</table>
<p>事件适配器 </p>
<ol>
<li>ComponentAdapter( 组件适配器) </li>
<li>ContainerAdapter( 容器适配器) </li>
<li>FocusAdapter( 焦点适配器) </li>
<li>KeyAdapter( 键盘适配器) </li>
<li>MouseAdapter( 鼠标适配器) </li>
<li>MouseMotionAdapter( 鼠标运动适配器)</li>
<li>WindowAdapter( 窗口适配器) </li>
</ol>
<p>可以创建一个全局的监听器，不过有时写成内部类会更有用。这不仅是因为将监听器类放在它们所服务的用户接口类或者业务逻辑类的内部时，可以在逻辑上对其进行分组，而且还因为内部类对象含有一个对其外部类对象的引用，这就为跨越类和子类系统边界的调用提供了一种优雅的方式。</p>
<p>Swing支持键盘快捷键，可以用键盘而不是鼠标来选择任何从AbstractButton继承而来的组件：只要使用重载的构造器，使它的第二个参数接受快捷键的标识符即可。如果没有这样的构造器，可以通过setMnemonic()方法<code>btn.setMnemonic(KeyEvent.VK_B)</code>。</p>
<p>setActionCommand()的用法。</p>
<figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//先设置 </span></span><br><span class="line">menuitem.setActionCommand<span class="params">(<span class="string">"Open"</span>)</span>;</span><br><span class="line"><span class="comment">//在事件处理器中</span></span><br><span class="line">JMenuItem target = <span class="params">(JMenuItem)</span>e.getSource<span class="params">()</span>;</span><br><span class="line">String actionCommand = target.getActionCommand<span class="params">()</span>;</span><br><span class="line"><span class="keyword">if</span><span class="params">(actionCommand.equals<span class="params">(<span class="string">"Open"</span>)</span>)</span>&#123;&#125;</span><br></pre></td></tr></table></figure>
<p>任何能够接受文本的组件都可以接受html文本，且能根据html的规则来重新格式化文本。必须使文本以<code>&lt;html&gt;</code>开始，然后就可以使用普通的html标记了，注意，不会强制要求你添加普通的结束标记。</p>
<p>选择外观<br>try {<br>    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());<br>} catch(Exception e) {<br>    throw new RuntimeException(e);<br>}<br>不过你要确保在创建任何可视组件之前先调用这些代码。</p>
<h3 id="绘图">绘图</h3><ol>
<li><p>paint方法</p>
<p> public void paint(Graphics g)       以画布为参数，在画布上执行画图方法 </p>
</li>
<li><p>repaint方法</p>
<p> Applet重画时系统自动调用paint方法</p>
</li>
<li><p>update方法</p>
<p> public void update(Graphics g)       更新容器，向repaint发出刷新小应用程序的信号，缺省的update方法清除Applet画图区并调用paint方法</p>
</li>
</ol>
<p><strong>Graphics类</strong></p>
<p>Graphics类提供画各种图形的方法，其中包括线、圆和椭圆、矩形和多边形、图像以及各种字体的文本等。这些方法具体如下：</p>
<p>public abstract void clipRect(int x, int y, int width, int height)        指定的区域切分<br>public abstract void drawLine(int x1, int y1, int x2, int y2) 使用当前颜色，在点(x1, y1) 和 (x2, y2) 之间画线<br>public abstract void drawOval(int x, int y, int width, int height) 画椭圆<br>public abstract void fillOval(int x, int y, int width, int height) 画实心椭圆<br>public abstract void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) 画x和y坐标定义的多边形<br>public void drawRect(int x, int y, int width, int height) 画矩形<br>public void fillRect(int x, int y, int width, int height) 画实心矩形<br>public abstract void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) 画圆角矩形<br>public abstract void drawString(String str, int x, int y) 使用当前字体和颜色画字符串str<br>public abstract void setColor(Color c) 设置图形上下文的当前颜色<br>public abstract void setPaintMode() 设置画模式<br>public abstract boolean drawImage (Image img, int x, int y, ImageObserver observer) 画特定图<br>public abstract void setFont(Font font) 设置特定的font字体。使用时首先得到font对象的一个实例，Font类常用构造函数为：public Font(String name, int style, int size) </p>
<p>Color类</p>
<p><code>public Color(int red, int green, int blue)</code><br><code>public Color(int red, int green, int blue, int alpha)</code>       其中：前三个分量即RGB颜色模式中的参数，第四个alpha分量指透明的程度。当alpha分量为255时，表示完全不透明，正常显示；当alpha分量为0时，表示完全透明，前三个分量不起作用</p>
<p>Graphics2D类</p>
<p>Graphics2D类继承于Graphics类，提供几何学、坐标变换、颜色管理以及文本排列等的更高级控制。Graphics2D类是Java平台上渲染二维图形、文字、以及图片的基础类，提供较好的对绘制形状、填充形状、旋转形状、绘制文本、绘制图像以及定义颜色的支持。在AWT编程接口中，用户通过paint方法接收Graphics对象作为参数，若是使用Graphics2D类，就需要在Paint方法中进行强制转换。</p>
<figure class="highlight aspectj"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">void</span> <span class="title">paint</span><span class="params">(Graphics old)</span></span>&#123;	Graphics2D <span class="keyword">new</span> = (Graphics2D)old;&#125;</span><br></pre></td></tr></table></figure>
<p>Graphics2D提供以下两个方法进行形状的绘制：<br>public abstract void draw(Shape s)         根据Graphics2D的环境设置画出形状s。<br>public abstract void fill(Shape s)         画实心形状s。</p>
<p>Shape的实现类：Line2D（线）、Rectangle2D（矩形）、RoundRectangle2D（圆角矩形）、Ellipse2D（椭圆）、GeneralPath（几何路径）。</p>
<h2 id="Swing与并发">Swing与并发</h2><h3 id="长期运行的任务">长期运行的任务</h3><p>在专用线程中执行长时间 GUI 交互任务的抽象类。 </p>
<p>使用 Swing 编写多线程应用程序时，要记住两个约束条件：（有关详细信息，请参阅 How to Use Threads）： </p>
<ul>
<li>不应该在事件指派线程 上运行耗时任务。否则应用程序将无响应。 </li>
<li>只能在事件指派线程 上访问 Swing 组件。 </li>
</ul>
<p>这些约束意味着需要时间密集计算操作的 GUI 应用程序至少需要以下两个线程：1) 执行长时间任务的线程； 2) 所有 GUI 相关活动的事件指派线程 （EDT）这涉及到难以实现的线程间通信。 </p>
<p>SwingWorker 设计用于需要在后台线程中运行长时间运行任务的情况，并可在完成后或者在处理过程中向 UI 提供更新。SwingWorker 的子类必须实现 doInBackground() 方法，以执行后台计算。 </p>
<p>工作流 </p>
<p>SwingWorker 的生命周期中包含三个线程： </p>
<ul>
<li>当前线程：在此线程上调用 execute() 方法。它调度 SwingWorker 以在 worker 线程上执行并立即返回。可以使用 get 方法等待 SwingWorker 完成。 </li>
<li>Worker 线程：在此线程上调用 doInBackground() 方法。所有后台活动都应该在此线程上发生。要通知 PropertyChangeListeners 有关绑定 (bound) 属性的更改，请使用 firePropertyChange 和 getPropertyChangeSupport() 方法。默认情况下，有两个可用的绑定属性：state 和 progress。 </li>
<li>事件指派线程：所有与 Swing 有关的活动都在此线程上发生。SwingWorker 调用 process 和 done() 方法，并通知此线程的所有 PropertyChangeListener。 </li>
</ul>
<p>通常，当前 线程就是事件指派线程。 </p>
<p>在 worker 线程上调用 doInBackground 方法之前，SwingWorker 通知所有 PropertyChangeListener 有关对 StateValue.STARTED 的 state 属性更改。doInBackground 方法完成后，执行 done 方法。然后 SwingWorker 通知所有 PropertyChangeListener 有关对 StateValue.DONE 的 state 属性更改。 </p>
<p>SwingWorker 被设计为只执行一次。多次执行 SwingWorker 将不会调用两次 doInBackground 方法。 </p>
<p>示例用法 </p>
<p>下例说明了最简单的使用范例：在后台完成某些处理，并在处理完成后更新 Swing 组件。 </p>
<p>假定想找到“Meaning of Life”并在 JLabel 中显示结果。 </p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">final</span> <span class="type">JLabel</span> label;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MeaningOfLifeFinder</span> <span class="keyword"><span class="keyword">extends</span></span> <span class="title">SwingWorker&lt;String</span>, <span class="title">Object&gt;</span> &#123;</span></span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  public <span class="type">String</span> doInBackground() &#123;</span><br><span class="line">    <span class="keyword">return</span> findTheMeaningOfLife();</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="keyword">protected</span> void done() &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123; </span><br><span class="line">      label.setText(get());</span><br><span class="line">    &#125; <span class="keyword">catch</span> (<span class="type">Exception</span> ignore) &#123;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line">(<span class="keyword">new</span> <span class="type">MeaningOfLifeFinder</span>()).execute();</span><br></pre></td></tr></table></figure>
<h3 id="可视化线程机制">可视化线程机制</h3><p>调用repaint时，并未强制在这一时刻立即进行绘制，而只是设置了一个“脏标识”，表示当下一次事件分发线程准备好重绘时，这个区域是重绘的备选元素之一。</p>
<p>当事件分发线程实际执行paint时，首先调用paintComponent，然后是paintBorder和paintChildren。如果需要在导出组件中覆盖paint，就必须牢记调用基类版本的paint，以使得它仍旧可以执行正确的行为。</p>
<h2 id="可视化编程与JavaBean">可视化编程与JavaBean</h2><h3 id="什么是JavaBean">什么是JavaBean</h3><p>JavaBean 只是一个命名规则</p>
<ol>
<li>对于一个名称为xxx的属性，通常你要写两个方法；getXxx()和setXxx()。任何浏览这些方法的工具，都会把get或sett后面的第一个字母自动转换为小写，以产生属性名，get方法返回的类型要与set方法里参数的类型相同属性的名称与set和get所依据的类型毫无关系</li>
<li>对于布尔型属性可以使用以上get和set的方式，不过也可以把get替换成is</li>
<li>Bean的普通方法不必遵循以上命名规则，不过它们必须是public的。</li>
<li>对于事件，要使用Swing中处理监听器的方式。这与前面所见到的完全相同addBounceListener( BounceListener)和 removeBounceListener (BounceListener)用来处理BounceEvent事件。大多数情况下，内置的事件和监听器就能够满足需求了，不过也可以自己编写事件和监听器接口。</li>
</ol>
<h3 id="使用Introspector抽取BeanInfo">使用Introspector抽取BeanInfo</h3><p>Introspector（内省器），这个类最重要的就是静态的getBeanInfo方法。向这个方法传递一个Class对象引用，它能够完全侦测这个类，然后返回一个BeanInfo对象，可以通过这个对象得到Bean的属性、方法和事件。</p>
<figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br></pre></td><td class="code"><pre><span class="line">public class BeanDumper extends JFrame &#123;  </span><br><span class="line">    private JTextField query = new JTextField<span class="params">(<span class="number">20</span>)</span>;  </span><br><span class="line">    private JTextArea results = new JTextArea<span class="params">()</span>;  </span><br><span class="line">  </span><br><span class="line">    public void print<span class="params">(String s)</span> &#123;  </span><br><span class="line">        results.append<span class="params">(s + <span class="string">" \n"</span>)</span>;  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    public void dump<span class="params">(Class&lt;?&gt; bean)</span> &#123;  </span><br><span class="line">        results.setText<span class="params">(<span class="string">""</span>)</span>;  </span><br><span class="line">        BeanInfo bi = null;  </span><br><span class="line">  </span><br><span class="line">        try &#123;  </span><br><span class="line">            bi = Introspector.getBeanInfo<span class="params">(bean, Object.class)</span>;  </span><br><span class="line">        &#125; catch <span class="params">(IntrospectionException e)</span> &#123;  </span><br><span class="line">            System.out.println<span class="params">(<span class="string">"Couldn 't introspect"</span> + bean.getName<span class="params">()</span>)</span>;  </span><br><span class="line">            return;  </span><br><span class="line">        &#125;  </span><br><span class="line">        <span class="comment">// 获取 bean属性 方法  </span></span><br><span class="line">        <span class="keyword">for</span> <span class="params">(PropertyDescriptor d : bi.getPropertyDescriptors<span class="params">()</span>)</span> &#123;  </span><br><span class="line">            Class&lt;?&gt; p = d.getPropertyType<span class="params">()</span>;  </span><br><span class="line">            <span class="keyword">if</span> <span class="params">(p == null)</span>  </span><br><span class="line">                continue;  </span><br><span class="line">            System.out.println<span class="params">(<span class="string">"Property type:\n"</span> + p.getName<span class="params">()</span>)</span>;  </span><br><span class="line">            Method m = d.getReadMethod<span class="params">()</span>;  </span><br><span class="line">            <span class="keyword">if</span> <span class="params">(m != null)</span>  </span><br><span class="line">                System.out.println<span class="params">(<span class="string">"read method:+\n"</span> + m.getName<span class="params">()</span>)</span>;  </span><br><span class="line">            Method rm = d.getWriteMethod<span class="params">()</span>;  </span><br><span class="line">            <span class="keyword">if</span> <span class="params">(rm != null)</span>  </span><br><span class="line">                System.out.println<span class="params">(<span class="string">"write method:+\n"</span> + rm.getName<span class="params">()</span>)</span>;  </span><br><span class="line">            System.out.println<span class="params">(<span class="string">"===================================="</span>)</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line">        System.out.println<span class="params">(<span class="string">"public methods:"</span>)</span>;  </span><br><span class="line">        <span class="keyword">for</span> <span class="params">(MethodDescriptor ms : bi.getMethodDescriptors<span class="params">()</span>)</span> &#123;  </span><br><span class="line">            System.out.println<span class="params">(<span class="string">"ms:"</span> + ms.getMethod<span class="params">()</span>.toString<span class="params">()</span>)</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line">        System.out.println<span class="params">(<span class="string">"===================================="</span>)</span>;  </span><br><span class="line">        System.out.println<span class="params">(<span class="string">"envent support:"</span>)</span>;  </span><br><span class="line">        <span class="keyword">for</span> <span class="params">(EventSetDescriptor e : bi.getEventSetDescriptors<span class="params">()</span>)</span> &#123;  </span><br><span class="line">            System.out.println<span class="params">(<span class="string">"listener type:\n"</span>  </span><br><span class="line">                    + e.getListenerType<span class="params">()</span>.getName<span class="params">()</span>)</span>;  </span><br><span class="line">            <span class="keyword">for</span> <span class="params">(Method lm : e.getListenerMethods<span class="params">()</span>)</span>  </span><br><span class="line">                System.out.println<span class="params">(<span class="string">"listener method:\n"</span> + lm.getName<span class="params">()</span>)</span>;  </span><br><span class="line">  </span><br><span class="line">            <span class="keyword">for</span> <span class="params">(MethodDescriptor lmd : e.getListenerMethodDescriptors<span class="params">()</span>)</span>  </span><br><span class="line">                System.out.println<span class="params">(<span class="string">"listener methodDescriptor:\n"</span>  </span><br><span class="line">                        + lmd.getName<span class="params">()</span>)</span>;  </span><br><span class="line">            <span class="comment">//  </span></span><br><span class="line">            Method addListener = e.getAddListenerMethod<span class="params">()</span>;  </span><br><span class="line">            System.out.println<span class="params">(<span class="string">"add listener method:\n"</span> + addListener)</span>;  </span><br><span class="line">            Method removeListener = e.getRemoveListenerMethod<span class="params">()</span>;  </span><br><span class="line">            System.out.println<span class="params">(<span class="string">"Remove Listener Method:\n"</span> + removeListener)</span>;  </span><br><span class="line">            System.out.println<span class="params">(<span class="string">"==========================================="</span>)</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// ------------------------------------------------  </span></span><br><span class="line">    class Dumper implements ActionListener &#123;  </span><br><span class="line">  </span><br><span class="line">        @Override  </span><br><span class="line">        public void actionPerformed<span class="params">(ActionEvent e)</span> &#123;  </span><br><span class="line">            String name = query.getText<span class="params">()</span>;  </span><br><span class="line">            System.out.println<span class="params">(<span class="string">"name=========&gt;"</span>+name)</span>;  </span><br><span class="line">            Class&lt;?&gt; c = null;  </span><br><span class="line">            try &#123;  </span><br><span class="line">                c = Class.forName<span class="params">(name)</span>;  </span><br><span class="line">            &#125; catch <span class="params">(ClassNotFoundException e1)</span> &#123;  </span><br><span class="line">                results.setText<span class="params">(<span class="string">"couldn 't find "</span> + name)</span>;  </span><br><span class="line">                e1.printStackTrace<span class="params">()</span>;  </span><br><span class="line">                return;  </span><br><span class="line">            &#125;  </span><br><span class="line">            dump<span class="params">(c)</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    public BeanDumper<span class="params">()</span> &#123;  </span><br><span class="line">        JPanel p = new JPanel<span class="params">()</span>;  </span><br><span class="line">        p.setLayout<span class="params">(new FlowLayout<span class="params">()</span>)</span>;  </span><br><span class="line">        p.add<span class="params">(new JLabel<span class="params">(<span class="string">"qualifeied bean name:"</span>)</span>)</span>;  </span><br><span class="line">        p.add<span class="params">(query)</span>;  </span><br><span class="line">        add<span class="params">(BorderLayout.NORTH, p)</span>;  </span><br><span class="line">        add<span class="params">(new JScrollPane<span class="params">(results)</span>)</span>;  </span><br><span class="line">        Dumper dmpr = new Dumper<span class="params">()</span>;  </span><br><span class="line">        query.addActionListener<span class="params">(dmpr)</span>;  </span><br><span class="line">        query.setText<span class="params">(<span class="string">"org.rui.swing.bean.Frog"</span>)</span>;  </span><br><span class="line">        dmpr.actionPerformed<span class="params">(new ActionEvent<span class="params">(dmpr, <span class="number">0</span>, <span class="string">""</span>)</span>)</span>;  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    public static void main<span class="params">(String[] args)</span> &#123;  </span><br><span class="line">        <span class="comment">//工具类  </span></span><br><span class="line">        SwingConsole.run<span class="params">(new BeanDumper<span class="params">()</span>, <span class="number">600</span>, <span class="number">500</span>)</span>;  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="JavaBean与同步">JavaBean与同步</h3><ol>
<li>尽可能地让Bean中的所有公共方法都是synchronized的。</li>
<li>当一个多路事件触发了一组对该事件感兴趣的监听器时，你必须假定，在你遍历列表进行通知的同时，监听器可能会被添加或移除。<br> 可以通过忽略synchronized关键字并使用单路事件处理方式，回避并发问题。 </li>
</ol>
<figure class="highlight aspectj"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 这是这是一个单播侦听器  </span></span><br><span class="line"><span class="comment">// 最简单形式的侦听器管理  </span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">void</span> <span class="title">addActionListener</span><span class="params">(ActionListener l)</span>  </span><br><span class="line">        <span class="keyword">throws</span> TooManyListenersException </span>&#123;  </span><br><span class="line">    <span class="keyword">if</span> (actionListener != <span class="keyword">null</span>) &#123;  </span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> TooManyListenersException();  </span><br><span class="line">    &#125;  </span><br><span class="line">    actionListener = l;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>判断方法是否被同步需要考虑的问题</p>
<ol>
<li>这个方法会修改对象中“关键”变量的状态吗？要弄清楚变量是否“关键”，必须判断它们是否被程序中的其他线程读写。</li>
<li>这个方法依赖于那些“关键”变量吗？如果有某个同步方法会修改此方法所使用的变量，那么你应该把这个方法也同步。要是觉得问题不大，这种改变只起瞬时作用，你就可以做出不同步的决定，以避免同步方法调用所产生的开销。</li>
<li>第三个线索是查看基类版本的paintComponent是否同步，这只是一个线索。注意，同步不会继承，也就是说，基类方法是同步的，派生类中覆盖后的版本并非自动同步。</li>
<li>方法执行必须尽可能快。要尽可能把处理的开销移到方法外面。</li>
</ol>
<h3 id="对Bean更高级的支持">对Bean更高级的支持</h3><p>前面的例子只演示了单一属性，但也可以使用数组来表示多重属性。这称为索引属性。<br>属性可以被绑定，即它们能通过PropertyChangeEvent事件通知其他对象<br>属性可以被约束，即如果属性的改变是不可接受的，其他对象可以否决这个改变。</p>
<p>Swing的可替代选择flex，SWT</p>

      
    </div>
    <footer class="article-footer">
	  
	  <!-- 百度分享 Start -->
	  <div class="bdsharebuttonbox"><a href="#" class="bds_more" data-cmd="more"></a><a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间"></a><a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博"></a><a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博"></a><a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网"></a><a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信"></a></div>
	  <!-- 百度分享 End -->
	  
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Thinking-in-Java/">Thinking in Java</a></li></ul>

	  
<span>
Updated:<time datetime="2015-02-08T13:12:54.000Z" itemprop="dateModified">2015-02-08</time>
</span>


    </footer>
  </div>
  
    
<nav id="article-nav">
  
    <a href="/2015/03/05/hibernate-note/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Newer</strong>
      <div class="article-nav-title">
        
          Hibernate笔记
        
      </div>
    </a>
  
  
    <a href="/2015/02/06/thinking-in-java-note-8/" id="article-nav-older" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Older</strong>
      <div class="article-nav-title">Java编程思想笔记八</div>
    </a>
  
</nav>

  
</article>



<!-- 多说评论框 start -->

<section id="comments">
  <div class="ds-thread"  data-thread-key="/2015/02/07/thinking-in-java-note-9/" data-title="Java编程思想笔记九" data-url="http://howiefh.github.io/2015/02/07/thinking-in-java-note-9/" id="ds_thread">
    <noscript>Please enable JavaScript to view the <a href="//duoshuo.com/?ref_noscript">comments powered by duoshuo.</a></noscript>
  </div>
</section>

<!-- 多说评论框 end -->
</section>
        
          
  <div id="toc" class="toc-aside">
  <h2 class="toc-title">Contents</h2>
    
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#Swing_基础"><span class="toc-number">1.</span> <span class="toc-text">Swing 基础</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#组件"><span class="toc-number">1.1.</span> <span class="toc-text">组件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#布局管理"><span class="toc-number">1.2.</span> <span class="toc-text">布局管理</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#事件"><span class="toc-number">1.3.</span> <span class="toc-text">事件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#绘图"><span class="toc-number">1.4.</span> <span class="toc-text">绘图</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Swing与并发"><span class="toc-number">2.</span> <span class="toc-text">Swing与并发</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#长期运行的任务"><span class="toc-number">2.1.</span> <span class="toc-text">长期运行的任务</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#可视化线程机制"><span class="toc-number">2.2.</span> <span class="toc-text">可视化线程机制</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#可视化编程与JavaBean"><span class="toc-number">3.</span> <span class="toc-text">可视化编程与JavaBean</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是JavaBean"><span class="toc-number">3.1.</span> <span class="toc-text">什么是JavaBean</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#使用Introspector抽取BeanInfo"><span class="toc-number">3.2.</span> <span class="toc-text">使用Introspector抽取BeanInfo</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#JavaBean与同步"><span class="toc-number">3.3.</span> <span class="toc-text">JavaBean与同步</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#对Bean更高级的支持"><span class="toc-number">3.4.</span> <span class="toc-text">对Bean更高级的支持</span></a></li></ol></li></ol>
    
  </div>

<aside id="sidebar">

  
    
<div class="widget-wrap">
  <h3 class="widget-title">ABOUT ME</h3>
  <ul class="widget about-me">
    
    <li><img class="author" title="About me" src="http://fh-1.qiniudn.com/okal-eltocat.jpg" /></li>
    
    
    <li>Hi,I'm FengHao.</li>
    
    <li>I'll share something interesting and my learning experience with you at this blog.</li>
    
    <li>前博客:<a href="http://hi.baidu.com/idea_star" target="_BLANK">百度空间</a></li>
    
  </ul>
</div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Categories</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/Android/">Android</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/C/">C</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Database/">Database</a><span class="category-list-count">13</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/Database/MongoDB/">MongoDB</a><span class="category-list-count">10</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Database/MySQL/">MySQL</a><span class="category-list-count">2</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/Eclipse/">Eclipse</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/FTP/">FTP</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Git/">Git</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Hexo/">Hexo</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Java/">Java</a><span class="category-list-count">20</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/Java/FreeMarker/">FreeMarker</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Java/Shiro/">Shiro</a><span class="category-list-count">2</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/JavaEE/">JavaEE</a><span class="category-list-count">4</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/JavaEE/Hibernate/">Hibernate</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/JavaEE/JSP/">JSP</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/JavaEE/Spring/">Spring</a><span class="category-list-count">2</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/JavaScript/">JavaScript</a><span class="category-list-count">5</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/JavaScript/jQuery/">jQuery</a><span class="category-list-count">1</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/Linux/">Linux</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/PHP/">PHP</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Suse/">Suse</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Ubuntu/">Ubuntu</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Vim/">Vim</a><span class="category-list-count">8</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/编程/">编程</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/软件/">软件</a><span class="category-list-count">1</span></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tag Cloud</h3>
    <div class="widget tagcloud">
      <a href="/tags/Android/" style="font-size: 14.75px; color: #65bfa7">Android</a> <a href="/tags/C/" style="font-size: 13.88px; color: #71c1c2">C</a> <a href="/tags/CAS/" style="font-size: 13px; color: #7dc3de">CAS</a> <a href="/tags/Chrome/" style="font-size: 13px; color: #7dc3de">Chrome</a> <a href="/tags/Clean-Code/" style="font-size: 13.88px; color: #71c1c2">Clean Code</a> <a href="/tags/Database/" style="font-size: 13px; color: #7dc3de">Database</a> <a href="/tags/Eclipse/" style="font-size: 13px; color: #7dc3de">Eclipse</a> <a href="/tags/FTP/" style="font-size: 13.88px; color: #71c1c2">FTP</a> <a href="/tags/FreeMarker/" style="font-size: 14.75px; color: #65bfa7">FreeMarker</a> <a href="/tags/Gcc/" style="font-size: 13px; color: #7dc3de">Gcc</a> <a href="/tags/Git/" style="font-size: 14.75px; color: #65bfa7">Git</a> <a href="/tags/Github-Pages/" style="font-size: 13px; color: #7dc3de">Github Pages</a> <a href="/tags/Hexo/" style="font-size: 14.75px; color: #65bfa7">Hexo</a> <a href="/tags/Hibernate/" style="font-size: 13px; color: #7dc3de">Hibernate</a> <a href="/tags/JSP/" style="font-size: 13px; color: #7dc3de">JSP</a> <a href="/tags/JVM/" style="font-size: 14.75px; color: #65bfa7">JVM</a> <a href="/tags/Java/" style="font-size: 14.75px; color: #65bfa7">Java</a> <a href="/tags/JavaMail/" style="font-size: 13px; color: #7dc3de">JavaMail</a> <a href="/tags/JavaScript/" style="font-size: 16.5px; color: #4dbc6f">JavaScript</a> <a href="/tags/Linux/" style="font-size: 13.88px; color: #71c1c2">Linux</a> <a href="/tags/Log/" style="font-size: 13px; color: #7dc3de">Log</a> <a href="/tags/Markdown/" style="font-size: 13.88px; color: #71c1c2">Markdown</a> <a href="/tags/MongoDB/" style="font-size: 20px; color: #1db400">MongoDB</a> <a href="/tags/MySQL/" style="font-size: 13.88px; color: #71c1c2">MySQL</a> <a href="/tags/PHP/" style="font-size: 16.5px; color: #4dbc6f">PHP</a> <a href="/tags/Rhythmbox/" style="font-size: 13px; color: #7dc3de">Rhythmbox</a> <a href="/tags/SSO/" style="font-size: 13px; color: #7dc3de">SSO</a> <a href="/tags/Servlet/" style="font-size: 13px; color: #7dc3de">Servlet</a> <a href="/tags/Shiro/" style="font-size: 13.88px; color: #71c1c2">Shiro</a> <a href="/tags/Spring/" style="font-size: 13.88px; color: #71c1c2">Spring</a> <a href="/tags/Suse/" style="font-size: 13px; color: #7dc3de">Suse</a> <a href="/tags/Thinking-in-Java/" style="font-size: 19.13px; color: #29b61c">Thinking in Java</a> <a href="/tags/Ubuntu/" style="font-size: 17.38px; color: #41ba53">Ubuntu</a> <a href="/tags/Vim/" style="font-size: 18.25px; color: #35b838">Vim</a> <a href="/tags/VirtualBox/" style="font-size: 13px; color: #7dc3de">VirtualBox</a> <a href="/tags/Vsftpd/" style="font-size: 13px; color: #7dc3de">Vsftpd</a> <a href="/tags/jQuery/" style="font-size: 13px; color: #7dc3de">jQuery</a> <a href="/tags/pam-mysql/" style="font-size: 13px; color: #7dc3de">pam_mysql</a> <a href="/tags/小米/" style="font-size: 13px; color: #7dc3de">小米</a> <a href="/tags/软件/" style="font-size: 15.63px; color: #59bd8b">软件</a>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/09/">September 2015</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/08/">August 2015</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/07/">July 2015</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/05/">May 2015</a><span class="archive-list-count">5</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/04/">April 2015</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/03/">March 2015</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/02/">February 2015</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/12/">December 2014</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/11/">November 2014</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/10/">October 2014</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/09/">September 2014</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/08/">August 2014</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/07/">July 2014</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/06/">June 2014</a><span class="archive-list-count">6</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/05/">May 2014</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/04/">April 2014</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/03/">March 2014</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">February 2014</a><span class="archive-list-count">11</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/01/">January 2014</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/12/">December 2013</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/11/">November 2013</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/08/">August 2013</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/07/">July 2013</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">June 2013</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/05/">May 2013</a><span class="archive-list-count">5</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/04/">April 2013</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2012/03/">March 2012</a><span class="archive-list-count">1</span></li></ul>
    </div>
  </div>


  
    <div class="widget-wrap">
  <h3 class="widget-title">Calendar</h3>
  <div class="widget">
    <div id="g-calendar" class="g-calendar">
        <span class="g-calendar-prev"></span>
		 
        <span class="g-calendar-back"></span>
        <span class="g-calendar-now"></span>
		 
        <span class="g-calendar-next"></span>
        <div class="g-calendar-hd"></div>
        <div class="g-calendar-tit"></div>
        <div class="g-calendar-bd"></div>
    </div>
  </div>
</div>
<script type="text/javascript">
function LGY_calendar(wrapId, options){
    this.oWrap = this.getId(wrapId);
    this.oHead = this.getByClassName('g-calendar-hd',this.oWrap)[0];
    this.oBody = this.getByClassName('g-calendar-bd',this.oWrap)[0];
    this.oTit = this.getByClassName('g-calendar-tit',this.oWrap)[0];
    this.oPrev = this.getByClassName('g-calendar-prev',this.oWrap)[0];
    this.oNext = this.getByClassName('g-calendar-next',this.oWrap)[0];
    this.oNow = this.getByClassName('g-calendar-now',this.oWrap)[0];
    this.oBack = this.getByClassName('g-calendar-back',this.oWrap)[0];
    this.init();
}
LGY_calendar.prototype = {
    ///////////获取ID元素
    getId:function(id){
        return document.getElementById(id);
    },
    ////////获取css类名元素
    getByClassName:function(className,parent){
        var elem = [],
            node = parent != undefined&&parent.nodeType==1?parent.getElementsByTagName('*'):document.getElementsByTagName('*'),
            p = new RegExp("(^|\\s)"+className+"(\\s|$)");
        for(var n=0,i=node.length;n<i;n++){
            if(p.test(node[n].className)){
                elem.push(node[n]);
            }
        }
        return elem;
    },
    //填充日历
    fillDate:function(year,month){
        //本月份第一天是星期几-为显示上个月的天数做铺垫
        var first_day = new Date(year,month,1).getDay(),
        //如果刚好是星期天，则空出一行（显示上个月的天数）
            first_day = first_day == 0?first_day=7:first_day;
        //本月份最后一天是几号
        var final_date = new Date(year,month+1,0).getDate(),
        //上个月的最后一天是几号
            last_date = new Date(year,month,0).getDate(),
        //剩余的格子数--即排在末尾的格子数
            surplus = 42 - first_day - final_date;
        //设置年的链接
        var yearHead = "<a href='/" + "archives/" + year + "/'>" + year + " "+ "</a>"; 
        //设置年的链接
        var monthHead = "";
        var month1 = month + 1;
        if (month1 < 10) {
            monthHead = "<a href='/" + "archives/" + year + "/" + "0" + month1 + "/'>" + " " + month1 + " " + "</a>";
        } else {
            monthHead = "<a href='/" + "archives/" + year + "/" + month1 + "/'>" + " " + month1 + " " + "</a>";
        }
        //设置表头的日历
        this.oHead.innerHTML = yearHead+'年'+monthHead+'月';
        //填充日历执行
        var html = '';
        //上个月的显示天数
        for(var i=0;i<first_day;i++){
            html+='<span class="g-calendar-grey">'+(last_date-(first_day-1)+i)+'</span>';
        }
        //本月的显示天数
        var postdate = new Date("Sat Feb 07 2015 20:51:16 GMT+0800"); 
        if (true && postdate.getFullYear() == year && postdate.getMonth() == month) { 
            html += '<span>1</span><span>2</span><span>3</span><span>4</span><span>5</span><span><a href="/2015/02/06/thinking-in-java-note-8/" title="Java编程思想笔记八">6</a></span><span><a href="/2015/02/07/thinking-in-java-note-9/" title="Java编程思想笔记九">7</a></span><span>8</span><span>9</span><span>10</span><span>11</span><span>12</span><span>13</span><span>14</span><span>15</span><span>16</span><span>17</span><span>18</span><span>19</span><span>20</span><span>21</span><span>22</span><span>23</span><span>24</span><span>25</span><span>26</span><span>27</span><span>28</span><span>29</span><span>30</span><span>31</span>';
        } else {
            for(var j=0;j<final_date;j++){        
                html+='<span id="d'+(j+1)+'">'+(j+1)+'</span>';
            }
        }
        //下个月的显示天数
        for(var k=0;k<surplus;k++){
            html+='<span class="g-calendar-grey">'+(k+1)+'</span>';
        }
        //fill
        this.oBody.innerHTML = html;
        // 当前状态
        if(year==this.c_year&&this.c_month==month){
            this.oBody.getElementsByTagName('span')[first_day+this.date-1].className='g-calendar-on';
        }

        // 对所有文章遍历,然后将有文章的日期加上链接,如果文章太多的话,生成页面会很大,去掉了
        
    },
    // next切换
    next:function(){
        var _that = this;
        this.oNext.onclick = function(){
            _that.month++;
            if(_that.month>11){
                _that.month = 0;
                _that.year++;
            }
            // 填充日历
            _that.fillDate(_that.year,_that.month);
        };
    },
    // back 切换
    back:function(){
        var _that = this;
        if(this.oBack != undefined) {
            this.oBack.onclick = function(){
                var postdate = new Date("Sat Feb 07 2015 20:51:16 GMT+0800"); 
                _that.year = postdate.getFullYear();
                _that.month = postdate.getMonth();
                // 填充日历
                _that.fillDate(_that.year,_that.month);
            };
        }
    },
    // now切换
    now:function(){
        var _that = this;
        if(this.oNow != undefined ) {
            this.oNow.onclick = function(){
                var nowDate = new Date(); 
                _that.year = nowDate.getFullYear();
                _that.month = nowDate.getMonth();
                // 填充日历
                _that.fillDate(_that.year,_that.month);
            };
        }
    },
    // prev切换
    prev:function(){
        var _that = this;
        this.oPrev.onclick = function(){
            _that.month--;
            if(_that.month<0){
                _that.month = 11;
                _that.year--;
            }
            // 填充日历
            _that.fillDate(_that.year,_that.month);
        };
    },
    init:function(){
        this.oTit.innerHTML = '<span>日</span><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span>';
        // 获取今天的日历时间
        var now = new Date();
        this.c_year = this.year = now.getFullYear();
        this.c_month = this.month = now.getMonth();
        this.date = now.getDate();
        // 初始化--填充日历
        this.fillDate(this.year,this.month);
        //next切换
        this.next();
        //prev切换
        this.prev();
        //back 切换
        this.back();
        //now 切换
        this.now();
    }
}
new LGY_calendar('g-calendar');
</script>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recent Posts</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2015/09/01/javascript-summary/">JavaScript 总结</a>
          </li>
        
          <li>
            <a href="/2015/08/28/javascript-oop-function-expression-and-async/">JavaScript 面向对象程序设计、函数表达式和异步编程</a>
          </li>
        
          <li>
            <a href="/2015/08/28/javascript-reference-type/">JavaScript 引用类型</a>
          </li>
        
          <li>
            <a href="/2015/08/28/javascript-grammar/">JavaScript 基本语法</a>
          </li>
        
          <li>
            <a href="/2015/08/10/java-web/">Java Web 笔记</a>
          </li>
        
      </ul>
    </div>
  </div>


  
    
<div class="widget-wrap">
  <h3 class="widget-title">Recent Comments</h3>
  <ul class="widget ds-recent-comments" data-num-items="5" data-show-avatars="0" data-show-title="1" data-show-time="1"></ul>
</div>
<!-- 需要多说的公用代码 -->


  

</aside>

        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2015 howiefh<br>
      Powered by <a href="http://zespia.tw/hexo/" target="_blank">Hexo</a> and Theme by <a href="https://github.com/howiefh/hexo-theme-landscape-f" target="_blank" title="Landscape-F">Landscape-F</a>
    </div>
  </div>
</footer>

    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">Home</a>
  
    <a href="/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    

<!-- 多说公共JS代码 start (一个网页只需插入一次) -->

<script type="text/javascript">
  var duoshuoQuery = {short_name:"howiefh"};
  (function() {
	var ds = document.createElement('script');
	ds.type = 'text/javascript';ds.async = true;
	ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
	ds.charset = 'UTF-8';
	(document.getElementsByTagName('head')[0] 
		|| document.getElementsByTagName('body')[0]).appendChild(ds);
  })();
</script> 

<!-- 多说公共JS代码 end -->

<!-- 百度分享 start -->

<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":["mshare","douban","bdysc","sqq","qq","hi","baidu","huaban","youdao","sdo","mail","xg","diandian","fx","copy","print"],"bdPic":"","bdStyle":"1","bdSize":"16"},"share":{},"image":{"viewList":["qzone","tsina","tqq","renren","weixin"],"viewText":"分享到：","viewSize":"16"}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>

<!-- 百度分享 end -->

<!--
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="/js/jquery.min.js"></script>
-->
<script src="/js/jquery.min.js" type="text/javascript"></script>


  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css" type="text/css">
  <script src="/fancybox/jquery.fancybox.pack.js" type="text/javascript"></script>


<div class="bottom-btn">

	<a class="icon-gotop" href="javascript:void(0)" title="返回顶部"></a>
	<script src="/js/gotop.js" type="text/javascript"></script>
	<!--
	<script src="/js/gotop.js"></script>
	-->


	<a class="icon-toc-toggle" href="javascript:void(0)" title="文章目录"></a>
	<!--
	<script src="/js/toc_aside_toggle.js"></script>
	-->

</div>
<script src="/js/toc_aside_toggle.js" type="text/javascript"></script>


<script src="/js/script.js" type="text/javascript"></script>

  </div>
</body>
</html>
